{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Using Qasm in Qiskit\n",
    "\n",
    "You can write quantum programs in qasm quantum assembly code.\n",
    "\n",
    "We say \"qasm\" meaning the currently supported quantum assembly language.\n",
    "\n",
    "See:\n",
    "* [OPENQASM 2.x](https:arxiv.org/abs/1707.03429)\n",
    "* [Qiskit/openqasm: Gate and operation specification for ... - GitHub](https://github.com/Qiskit/openqasmhttps://github.com/Qiskit/openqasm)\n",
    "\n",
    "You can use Qiskit to execute your quantum programs on any supported backend.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Backends\n",
    "\n",
    "Backends are environments which run your code.\n",
    "\n",
    "All of the \"real\" work of quantum processing takes place \"remotely\". Here, \"remotely\" may possibly mean \"in the Qiskit Aer simulator on the user's own workstation\". In that case, communication still takes place in the same communication model, whether it's a local simulator, a remote simulator in the cloud, or a remote IBM Q quantum processing unit in the cloud.\n",
    "\n",
    "Generally the backends you encounter will be one of the following:\n",
    "* the Qiskit Aer simulator running on your local workstation\n",
    "* the [IBM Q](https://quantum-computing.ibm.com) simulator running in the cloud\n",
    "* one of the [IBM Q](https://quantum-computing.ibm.com) cloud-hosted quantum processors\n",
    "\n",
    "Qiskit provides an abstract backend and communicates with backend implementations via protocols, such as [JSON](https://www.json.org/) documents.\n",
    "\n",
    "### Custom backends\n",
    "Qiskit is open source: anyone can write a backend implementation and host their own services reachable by Qiskit code.\n",
    "\n",
    "A backend may be\n",
    "* a simulator\n",
    "* an IBM Q (or other) quantum processor\n",
    "* an abacus operated by a clockwork automaton\n",
    "* a little old person in a backroom with paper and a pencil.\n",
    "\n",
    "The first two are implemented by Qiskit and IBM Q Experience. The latter two exotic possibilities mentioned above can be implemented by you or others when you create new backend implementations."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Primary Relevant Qiskit Components\n",
    "\n",
    "* [Qiskit Terra](https://github.com/Qiskit/qiskit-terra)\n",
    "  * qasm translation\n",
    "  * circuit generation\n",
    "  * communications to backend\n",
    "    * abstract backend\n",
    "* [Qiskit IBMQ Provider](https://github.com/Qiskit/qiskit-ibmq-provider)\n",
    "  * qiskit-ibmq-provider backend implementation for communications to IBMQ backend"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Qasm and Circuit\n",
    "\n",
    "Qasm quantum assembly language is a theoretical gate model which evolved independently of IBM in the quantum computing community.\n",
    "\n",
    "Theorists express quantum operations using linear algebraic expressions.\n",
    "\n",
    "Qasm high-level operators represent quantum operations taking arguments of register and other types.\n",
    "\n",
    "These textual specifications of operations are rendered into [circuit](https://github.com/Qiskit/qiskit-tutorials/blob/master/qiskit/terra/visualizing_a_quantum_circuit.ipynb) form. Those circuits are then [transpiled](https://github.com/Qiskit/qiskit-tutorials/blob/master/qiskit/terra/using_the_transpiler.ipynb) into a sequence of low-level operations of typically limited variety offered by the target backend.\n",
    "\n",
    "Qasm can express circuits and circuits can express qasm.\n",
    "\n",
    "Typically, your Qiskit program creates a Circuit from your qasm code. Transpilation happens automatically. Then your Qiskit program submits the circuit derived from your qasm code to the backend as a Job for execution.\n",
    "\n",
    "Programmable levels exist below the higher level of qasm. Such matters are part of [OpenPulse](https://arxiv.org/pdf/1809.03452.pdf).\n",
    "\n",
    "### Transpilation\n",
    "\n",
    "When qasm programs are **transpiled** (compiled with transformation) for backend consumption, they may be transpiled into longer or shorter strings of lower level operators called \"basis gates\", i.e., the limited set of operators physically or virtually implemented at the next level which will be receiving the transpilation output.\n",
    "\n",
    "Qiskit offers visibility into the output of transpilation."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Put it all together\n",
    "\n",
    "Now let's take a simple qasm program and run it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# importing Qiskit\n",
    "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister\n",
    "from qiskit import BasicAer, IBMQ, execute\n",
    "\n",
    "backend = BasicAer.get_backend('qasm_simulator') # run on local simulator by default\n",
    "\n",
    "# Uncomment the following lines to run on a real device\n",
    "# IBMQ.load_account()\n",
    "# from qiskit.providers.ibmq import least_busy\n",
    "# backend = least_busy(IBMQ.backends(operational=True, simulator=False))\n",
    "# print(\"the best backend is \" + backend.name())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# You might get your qasm by opening a file instead\n",
    "qasm_source = \"\"\"// yiqing line (one of many possible)\n",
    "OPENQASM 2.0;\n",
    "include \"qelib1.inc\";\n",
    "qreg q[3];\n",
    "creg c[3];\n",
    "h q[0];\n",
    "h q[1];\n",
    "h q[2];\n",
    "barrier q[0],q[1],q[2];\n",
    "measure q[0] -> c[0];\n",
    "measure q[1] -> c[1];\n",
    "measure q[2] -> c[2];\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "        ┌──────────┐ ░ ┌─┐      \n",
      "q_0: |0>┤ U2(0,pi) ├─░─┤M├──────\n",
      "        ├──────────┤ ░ └╥┘┌─┐   \n",
      "q_1: |0>┤ U2(0,pi) ├─░──╫─┤M├───\n",
      "        ├──────────┤ ░  ║ └╥┘┌─┐\n",
      "q_2: |0>┤ U2(0,pi) ├─░──╫──╫─┤M├\n",
      "        └──────────┘ ░  ║  ║ └╥┘\n",
      " c_0: 0 ════════════════╩══╬══╬═\n",
      "                           ║  ║ \n",
      " c_1: 0 ═══════════════════╩══╬═\n",
      "                              ║ \n",
      " c_2: 0 ══════════════════════╩═\n",
      "                                \n"
     ]
    }
   ],
   "source": [
    "# Create circuit\n",
    "circ = QuantumCircuit.from_qasm_str(qasm_source)\n",
    "from qiskit.compiler import transpile\n",
    "\n",
    "# View representation of the circuit from a trial transpilation\n",
    "# When the job executes, transpilation will take place again automatically\n",
    "print(transpile(circ, backend=backend))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Job Status: job has successfully run\n"
     ]
    }
   ],
   "source": [
    "# Number of shots to run the program (experiment); maximum is 8192 shots.\n",
    "shots = 256\n",
    "# Maximum number of credits to spend on executions.\n",
    "max_credits = 6\n",
    "job_exp = execute(circ, backend=backend, shots=shots,\n",
    "                  max_credits=max_credits, memory=True)\n",
    "from qiskit.tools.monitor import job_monitor\n",
    "\n",
    "# Monitor the job ... the status show below as output will change as the job progresses\n",
    "job_monitor(job_exp)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Result(backend_name='qasm_simulator', backend_version='2.0.0', header=Obj(backend_name='qasm_simulator', backend_version='2.0.0'), job_id='753f8619-e79c-462c-82ba-a22c64a388ff', qobj_id='9f1207ba-5646-4f73-987c-095bf281c147', results=[ExperimentResult(data=ExperimentResultData(counts=Obj(0x0=35, 0x1=34, 0x2=26, 0x3=25, 0x4=33, 0x5=35, 0x6=38, 0x7=30), memory=['0x6', '0x3', '0x7', '0x5', '0x4', '0x2', '0x2', '0x6', '0x3', '0x6', '0x5', '0x1', '0x4', '0x3', '0x4', '0x6', '0x2', '0x2', '0x5', '0x3', '0x7', '0x7', '0x2', '0x0', '0x0', '0x1', '0x7', '0x1', '0x1', '0x1', '0x1', '0x7', '0x2', '0x0', '0x6', '0x2', '0x6', '0x5', '0x3', '0x4', '0x5', '0x0', '0x7', '0x5', '0x0', '0x3', '0x2', '0x7', '0x1', '0x3', '0x2', '0x5', '0x5', '0x7', '0x6', '0x4', '0x5', '0x7', '0x6', '0x5', '0x6', '0x6', '0x6', '0x7', '0x3', '0x3', '0x0', '0x1', '0x6', '0x5', '0x7', '0x1', '0x1', '0x0', '0x2', '0x0', '0x6', '0x0', '0x0', '0x6', '0x1', '0x5', '0x1', '0x1', '0x2', '0x1', '0x0', '0x2', '0x1', '0x6', '0x4', '0x0', '0x7', '0x3', '0x6', '0x4', '0x4', '0x2', '0x4', '0x5', '0x4', '0x4', '0x3', '0x5', '0x3', '0x6', '0x5', '0x4', '0x5', '0x3', '0x3', '0x3', '0x3', '0x1', '0x4', '0x0', '0x4', '0x0', '0x6', '0x1', '0x3', '0x1', '0x2', '0x4', '0x2', '0x7', '0x0', '0x5', '0x3', '0x7', '0x4', '0x4', '0x0', '0x5', '0x4', '0x0', '0x7', '0x1', '0x5', '0x7', '0x5', '0x6', '0x6', '0x0', '0x1', '0x1', '0x7', '0x5', '0x4', '0x6', '0x7', '0x2', '0x5', '0x2', '0x6', '0x7', '0x2', '0x0', '0x6', '0x3', '0x6', '0x6', '0x7', '0x6', '0x0', '0x1', '0x6', '0x1', '0x0', '0x5', '0x5', '0x2', '0x3', '0x7', '0x5', '0x4', '0x0', '0x1', '0x6', '0x7', '0x5', '0x4', '0x4', '0x6', '0x0', '0x0', '0x4', '0x0', '0x6', '0x1', '0x7', '0x0', '0x5', '0x2', '0x3', '0x7', '0x3', '0x1', '0x1', '0x5', '0x4', '0x1', '0x5', '0x6', '0x5', '0x4', '0x5', '0x6', '0x4', '0x6', '0x1', '0x2', '0x1', '0x4', '0x6', '0x0', '0x5', '0x2', '0x2', '0x2', '0x4', '0x1', '0x7', '0x4', '0x0', '0x0', '0x4', '0x5', '0x5', '0x2', '0x1', '0x4', '0x3', '0x0', '0x2', '0x6', '0x6', '0x4', '0x3', '0x3', '0x6', '0x6', '0x7', '0x7', '0x0', '0x1', '0x0', '0x7', '0x0', '0x7', '0x5', '0x0', '0x4', '0x7', '0x1', '0x0']), header=Obj(clbit_labels=[['c', 0], ['c', 1], ['c', 2]], creg_sizes=[['c', 3]], memory_slots=3, n_qubits=3, name='circuit0', qreg_sizes=[['q', 3]], qubit_labels=[['q', 0], ['q', 1], ['q', 2]]), meas_level=2, name='circuit0', seed_simulator=638276239, shots=256, status='DONE', success=True, time_taken=0.0035185813903808594)], status='COMPLETED', success=True, time_taken=0.005647182464599609)\n"
     ]
    }
   ],
   "source": [
    "# See the entire result expressed as a dictionary\n",
    "result_exp = job_exp.result()\n",
    "print(result_exp)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'counts': {'0x5': 35, '0x4': 33, '0x1': 34, '0x3': 25, '0x7': 30, '0x0': 35, '0x2': 26, '0x6': 38}, 'memory': ['0x6', '0x3', '0x7', '0x5', '0x4', '0x2', '0x2', '0x6', '0x3', '0x6', '0x5', '0x1', '0x4', '0x3', '0x4', '0x6', '0x2', '0x2', '0x5', '0x3', '0x7', '0x7', '0x2', '0x0', '0x0', '0x1', '0x7', '0x1', '0x1', '0x1', '0x1', '0x7', '0x2', '0x0', '0x6', '0x2', '0x6', '0x5', '0x3', '0x4', '0x5', '0x0', '0x7', '0x5', '0x0', '0x3', '0x2', '0x7', '0x1', '0x3', '0x2', '0x5', '0x5', '0x7', '0x6', '0x4', '0x5', '0x7', '0x6', '0x5', '0x6', '0x6', '0x6', '0x7', '0x3', '0x3', '0x0', '0x1', '0x6', '0x5', '0x7', '0x1', '0x1', '0x0', '0x2', '0x0', '0x6', '0x0', '0x0', '0x6', '0x1', '0x5', '0x1', '0x1', '0x2', '0x1', '0x0', '0x2', '0x1', '0x6', '0x4', '0x0', '0x7', '0x3', '0x6', '0x4', '0x4', '0x2', '0x4', '0x5', '0x4', '0x4', '0x3', '0x5', '0x3', '0x6', '0x5', '0x4', '0x5', '0x3', '0x3', '0x3', '0x3', '0x1', '0x4', '0x0', '0x4', '0x0', '0x6', '0x1', '0x3', '0x1', '0x2', '0x4', '0x2', '0x7', '0x0', '0x5', '0x3', '0x7', '0x4', '0x4', '0x0', '0x5', '0x4', '0x0', '0x7', '0x1', '0x5', '0x7', '0x5', '0x6', '0x6', '0x0', '0x1', '0x1', '0x7', '0x5', '0x4', '0x6', '0x7', '0x2', '0x5', '0x2', '0x6', '0x7', '0x2', '0x0', '0x6', '0x3', '0x6', '0x6', '0x7', '0x6', '0x0', '0x1', '0x6', '0x1', '0x0', '0x5', '0x5', '0x2', '0x3', '0x7', '0x5', '0x4', '0x0', '0x1', '0x6', '0x7', '0x5', '0x4', '0x4', '0x6', '0x0', '0x0', '0x4', '0x0', '0x6', '0x1', '0x7', '0x0', '0x5', '0x2', '0x3', '0x7', '0x3', '0x1', '0x1', '0x5', '0x4', '0x1', '0x5', '0x6', '0x5', '0x4', '0x5', '0x6', '0x4', '0x6', '0x1', '0x2', '0x1', '0x4', '0x6', '0x0', '0x5', '0x2', '0x2', '0x2', '0x4', '0x1', '0x7', '0x4', '0x0', '0x0', '0x4', '0x5', '0x5', '0x2', '0x1', '0x4', '0x3', '0x0', '0x2', '0x6', '0x6', '0x4', '0x3', '0x3', '0x6', '0x6', '0x7', '0x7', '0x0', '0x1', '0x0', '0x7', '0x0', '0x7', '0x5', '0x0', '0x4', '0x7', '0x1', '0x0']}\n"
     ]
    }
   ],
   "source": [
    "# Let's just look at the result data from the result without the other overhead\n",
    "print(result_exp.data())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# A function to generate a little database of the result data\n",
    "def csv_str(description, sorted_keys, sorted_counts):\n",
    "    \"\"\"Generate a cvs as a string from sorted keys and sorted counts\"\"\"\n",
    "    csv = []\n",
    "    csv.append(description)\n",
    "    keys = \"\"\n",
    "    for key in sorted_keys:\n",
    "        keys += key + ';'\n",
    "    csv.append(keys)\n",
    "    counts = \"\"\n",
    "    for count in sorted_counts:\n",
    "        counts += str(count) + ';'\n",
    "    csv.append(counts)\n",
    "    return csv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "qasm_simulator 2019-08-06T08:48:27.268005\n",
      "000;001;010;011;100;101;110;111;\n",
      "35;34;26;25;33;35;38;30;\n"
     ]
    }
   ],
   "source": [
    "# Get the counts and keys from the result and convert to a csv\n",
    "counts_exp = result_exp.get_counts(circ)\n",
    "sorted_keys = sorted(counts_exp.keys())\n",
    "sorted_counts = []\n",
    "for i in sorted_keys:\n",
    "    sorted_counts.append(counts_exp.get(i))\n",
    "\n",
    "import datetime\n",
    "output = csv_str(str(backend) + ' ' + datetime.datetime.now().isoformat(),\n",
    "                 sorted_keys, sorted_counts)\n",
    "for line in output:\n",
    "    print(line)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
